#include "Communication.h"




CCommunication :: CCommunication()
{
    
    socketfd = -1;
    sockettype = SOCKET_MAX;
}

CCommunication :: ~CCommunication()
{
    close(socketfd);
}


int CCommunication :: SocketIntanceTCP(eSOCKETTYPE type, char * bindaddr, int bindport)
{
    int ret = -1;
    socketfd = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in addr = {0};
    addr.sin_family = AF_INET;
    addr.sin_port = htons(bindport);
    if(bindaddr != NULL)
       addr.sin_addr.s_addr = inet_addr(bindaddr);
    else
       addr.sin_addr.s_addr = htonl(INADDR_ANY);
   
    sockettype = type;
    if(SOCKET_SERVER == sockettype)
    {
        int flag = 1;
        int len = sizeof(flag);
        if(0 != (ret = setsockopt(socketfd , SOL_SOCKET , SO_REUSEADDR, (const void*)&flag, len)))
        {
           MY_ERROR_LOG("ret:%d socketfd : %d\n", ret, socketfd);
           return -1;
        }
    }
    if(SOCKET_SERVER == sockettype)
         ret = bind(socketfd, (struct sockaddr *)&addr, sizeof(addr));
    else
         return 0;
    return ret;
}

int CCommunication :: SocketIntanceUDP(eSOCKETTYPE type, char * bindaddr, int bindport)
{

    int ret = -1;
    socketfd = socket(AF_INET, SOCK_DGRAM, 0);
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(bindport);
    addr.sin_addr.s_addr = inet_addr(bindaddr);
    ret = bind(socketfd, (struct sockaddr *)&addr, sizeof(addr));
    sockettype = type;
    return ret;

}

int CCommunication :: SocketConnect(char *addrs, int port)
{
    if(socketfd < 0)
    {
        MY_ERROR_LOG("fd is invalid\n");
        return -1;
    }
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = inet_addr(addrs);
    return connect(socketfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));

}

int CCommunication :: SocketAccept(struct sockaddr_in *faraddr)
{
    if(NULL == faraddr)
    {
       MY_ERROR_LOG("faraddr is NULL\n");
       return -1;
    }
    socklen_t  len = sizeof(struct sockaddr);
    return accept(socketfd, (struct sockaddr *)faraddr, &len);
}

int CCommunication :: SocketListen(int maxcon)
{
    if(socketfd < 0)
    {
        MY_ERROR_LOG("fd is invalid\n");
        return -1;
    }
    return listen(socketfd, maxcon);
}

int CCommunication :: SocketWrite(char *data, int len)
{
    int ret = -1;
    fd_set   sets;
    FD_ZERO(&sets);
    FD_SET(socketfd, &sets);
    struct timeval timeout;
    timeout.tv_sec  = 0;
    timeout.tv_usec = 30 * 1000;
    ret = select(socketfd + 1, NULL, &sets, NULL, &timeout);
    if (ret > 0)
     {
        if (0 == FD_ISSET(socketfd, &sets)) 
        {
                    ret = 0;
                    return 0;
        }
        else 
            return send(socketfd, data, len, 0);
     }
     else if (0 == ret) 
     {
              return 0;
     } 
    return 0;
}

int CCommunication :: SocketWrite(int fd , char *data, int len)
{
    int ret = -1;
    fd_set   sets;
    FD_ZERO(&sets);
    FD_SET(fd, &sets);
    struct timeval timeout;
    timeout.tv_sec  = 0;
    timeout.tv_usec = 30 * 1000;
    ret = select(fd + 1, NULL, &sets, NULL, &timeout);
    if (ret > 0)
     {
        if (0 == FD_ISSET(fd, &sets)) 
        {
              ret = 0;
              return 0;
        }
        else 
              return send(fd, data, len, 0);
     }
     else if (0 == ret) 
     {
              return 0;
     } 
    return 0;
}


int CCommunication :: SocketRead(char *data, int len, int outtimems)
{
    fd_set fdset;
    FD_ZERO(&fdset);
    FD_SET(socketfd, &fdset);  
    struct timeval tm;
    tm.tv_sec = 0;
    tm.tv_usec = outtimems*1000;
    int ret = select(socketfd+1, &fdset, NULL, NULL, &tm);
    if(ret > 0)
    {
        if(FD_ISSET(socketfd, &fdset))
        { 
              if((ret = recv(socketfd, data, len, 0)) > 0)
                {   
                    return ret;
                }
                else
                {
                    if ((EINTR == errno) || (EAGAIN == errno) || (EWOULDBLOCK == errno) ||
                            (EPROTOTYPE == errno) || (EALREADY == errno) || (EINPROGRESS == errno))
                        return SOCKETTRYAGAIN;
                    else
                        return SOCKETDOWN;
                }
        }
        else
                return SOCKETTRYAGAIN;
    }
    else if(ret == 0)
    {
        return SOCKETTIMEOUT;
    }
    else
    {
        if (EINTR == errno) 
        {
            return SOCKETTRYAGAIN;
        }
        return SOCKETDOWN;
    }
    return SOCKETERROR;
}

int CCommunication :: SocketRead(int fd, char *data, int len, int outtimems)
{
    fd_set fdset;
    FD_ZERO(&fdset);
    FD_SET(fd, &fdset);  
    struct timeval tm;
    tm.tv_sec = 0;
    tm.tv_usec = outtimems*1000;
    int ret = select(fd+1, &fdset, NULL, NULL, &tm);
    if(ret > 0)
    {
        if(FD_ISSET(fd, &fdset))
        { 
              if((ret = recv(fd, data, len, 0)) > 0)
                {   
                    return ret;
                }
                else
                {
                    if ((EINTR == errno) || (EAGAIN == errno) || (EWOULDBLOCK == errno) ||
                            (EPROTOTYPE == errno) || (EALREADY == errno) || (EINPROGRESS == errno))
                        return SOCKETTRYAGAIN;
                    else
                        return SOCKETDOWN;
                }
        }
        else
                return SOCKETTRYAGAIN;
    }
    else if(ret == 0)
    {
        return SOCKETTIMEOUT;
    }
    else
    {
        if (EINTR == errno) 
        {
            return SOCKETTRYAGAIN;
        }
        return SOCKETDOWN;
    }
    return SOCKETERROR;
}

int CCommunication :: SocketClose(int fd)
{

   close(fd);
   return 0 ;
}


int CCommunication :: SocketFdGet()
{
    return socketfd;
}



 int CCommunication :: SocketGetAddrAndPort(struct sockaddr_in *sockaddr, char *addr, int addr_len, int &port)
 {
   
     if(NULL == sockaddr || NULL == addr)
        return -1;
 
     if(inet_ntop(sockaddr->sin_family, &sockaddr->sin_addr, addr, addr_len) == NULL)
        return -1;
     
     port = sockaddr->sin_port;
     return 0;
 }